package com.elias.share.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.util.StrUtil;
import com.elias.share.config.bean.FileInfo;
import com.elias.share.constants.Contants;
import com.elias.share.utils.FileDeleteQueueUtil;
import com.elias.share.utils.InstantUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Log4j2
@Component
public class FileDeleteTask implements ApplicationRunner {

    @Resource
    protected FileInfo fileInfo;

    @Override
    public void run(ApplicationArguments args) {
        new Thread(this::run).start();
    }

    private void run() {
        while (true) {
            try {
                Path take = FileDeleteQueueUtil.take();
                deleteFile(take);
            } catch (InterruptedException e) {
                log.error("Interrupted exception:", e);
            }
        }
    }

    private void deleteFile(Path path) {
        Instant start = Instant.now();
        File file = path.toFile();
        if (file.exists()) {
            long fileSize = file.length();
            boolean deleteSuccess = file.delete();
            if (deleteSuccess) {
                fileInfo.minusUsedSize(fileSize);
                log.info("delete expired file success,path:{},size:{},fileInfo:{},time:{}ms"
                        , file.getAbsolutePath(), DataSizeUtil.format(fileSize), fileInfo, InstantUtil.calcIntervalMilis(start));
            } else {
                log.error("delete file failed,path:{},size:{}", file.getAbsolutePath(), DataSizeUtil.format(fileSize));
            }
        } else {
            log.info("the file has been deleted");
        }
    }

    @Scheduled(cron = "${file.scan-expire-file}")
    public void scanExpireFile() {
        if (fileInfo.getUsedSize() == null) {
            return;
        }
        String location = fileInfo.getLocation();
        try (Stream<Path> pathStream = Files.walk(Paths.get(location))) {
            final long currentTimeMillis = System.currentTimeMillis();
            List<Path> list = pathStream.filter(Files::isRegularFile)
                    .filter(item -> {
                        String fileName = item.toFile().getName();
                        String millis = fileName;
                        int pointIndex = fileName.indexOf(Contants.STR_POINT);
                        if (pointIndex >= 0) {
                            millis = fileName.substring(0, pointIndex);
                        }
                        return StrUtil.isNotEmpty(millis)
                                && millis.matches("^[1-9][0-9]+$")
                                && currentTimeMillis >= Long.parseLong(millis);
                    }).collect(Collectors.toList());
            for (Path path : list) {
                FileDeleteQueueUtil.offer(path);
            }
        } catch (IOException e) {
            log.error("scan file exception,e:", e);
        }
    }
}
